import copy
import heapq
import math
import random
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.patches as mpatches
import itertools

import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


class WeightedGraphWithTasks:
    def __init__(self):
        self.graph = {}
        self.tasks = {}
        self.tasks_store = {}
        self.Xc1 = 0.65
        self.Xl1 = 0.35
        self.Xc2 = 0.65
        self.Xl2 = 0.35
        self.diff1 = 0.2
        self.diff2 = 0.2
        self.distance_L = {}  # 各个节点到图书馆的最小距离
        self.predecessors_L = {}  # 回图书馆的前驱
        self.matix=[]
        self.node_to_num = {}
        self.num_to_node = {}

    def modify_param(self, Xc1, Xl1, Xc2, Xl2, diff1, diff2):
        self.Xc1 = Xc1
        self.Xl1 = Xl1
        self.Xc2 = Xc2
        self.Xl2 = Xl2
        self.diff1 = diff1
        self.diff2 = diff2

    def add_edge(self, node1, node2, road_name, weight):
        if node1 not in self.graph:
            self.graph[node1] = {}
        if node2 not in self.graph:
            self.graph[node2] = {}
        self.graph[node1][node2] = {"road": road_name, "weight": weight}
        self.graph[node2][node1] = {"road": road_name, "weight": weight}

        # Add nodes to the node_to_num dictionary if they are not already present
        if node1 not in self.node_to_num:
            self.node_to_num[node1] = len(self.node_to_num)
        if node2 not in self.node_to_num:
            self.node_to_num[node2] = len(self.node_to_num)
    def init_num_to_node(self):
        self.num_to_node = {value: key for key, value in self.node_to_num.items()}
    def generate_matrix(self):
        # Initialize the matrix with zeros
        self.matix = [[0 for _ in range(len(self.node_to_num))] for _ in range(len(self.node_to_num))]

        # Fill the matrix with adjacency information
        for node, neighbors in self.graph.items():
            for neighbor in neighbors:
                self.matix[self.node_to_num[node]][self.node_to_num[neighbor]] = 1
                self.matix[self.node_to_num[neighbor]][self.node_to_num[node]] = 1

    def visualize_matrix(graph_with_tasks):
        G = nx.Graph()

        # 添加边和权重到网络X图中
        for node1, neighbors in graph_with_tasks.graph.items():
            for node2, details in neighbors.items():
                G.add_edge(node1, node2, weight=details['weight'])

        # 设置节点位置
        pos = node_positions

        # 创建一个字典，将节点名称映射到1到36的整数
        labels = {node: i + 1 for i, node in enumerate(graph_with_tasks.graph)}

        # 绘制无向图
        nx.draw_networkx_nodes(G, pos, node_size=800, node_color='skyblue', edgecolors='black', linewidths=1.4)
        nx.draw_networkx_edges(G, pos, edgelist=G.edges(), edge_color='gray', width=1.5, alpha=0.6)
        nx.draw_networkx_labels(G, pos, labels=labels, font_size=7, font_family="sans-serif", font_color='black')

        # 显示权重
        edge_labels = nx.get_edge_attributes(G, 'weight')
        nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_color='red')

        plt.axis('off')
        plt.title('Adjacency Matrix Visualization', fontsize=20)
        plt.show()
    def print_matrix(self):
        for row in self.matix:
            print(row)
    def add_task(self, building, books_to_return, books_to_borrow):
        """添加还书和借书任务"""
        if not isinstance(books_to_return, int) or not isinstance(books_to_borrow, int):
            raise ValueError("书籍数量必须为整数")
        self.tasks[building] = {"return": books_to_return, "borrow": books_to_borrow}

    def dijkstra(self, start):
        """Dijkstra算法实现，返回从起点到各点的最短路径长度"""
        distances = {node: float('inf') for node in self.graph}
        distances[start] = 0
        queue = [(0, start)]
        predecessors = {node: None for node in self.graph}
        while queue:
            current_distance, current_node = heapq.heappop(queue)
            if current_distance > distances[current_node]:
                continue
            for neighbor, details in self.graph[current_node].items():
                distance = current_distance + details['weight']
                if distance < distances[neighbor]:
                    distances[neighbor] = distance
                    predecessors[neighbor] = current_node
                    heapq.heappush(queue, (distance, neighbor))
        return distances, predecessors  # 额外返回前驱可以找到最短路径

    def calculate_total_time(self, route, speed):
        total_time = 0
        for i in range(len(route) - 1):
            """If the next node is '充电站1' and it is not the last node in the route, skip this iteration"""
            if route[i + 1] == '充电站1' and i != len(route) - 2:
                continue
            """Check if the next node is a valid key in the graph"""
            if route[i + 1] in self.graph[route[i]]:
                total_time += self.graph[route[i]][route[i + 1]]['weight'] / speed
        return total_time

    def find_route(self, current_node, next_node):  # 寻找路径 无头尾
        d, p = self.dijkstra(current_node)
        temp = next_node
        route = [next_node]
        if current_node == next_node:
            return []
        i = 1
        while p[temp] != current_node:
            route.insert(-i, p[temp])
            i += 1
            temp = p[temp]
        return route

    def combination(self, route):
        for j in range(len(route) - 1):
            isbefore = True
            for i in range(len(route)):
                if route[i] == '图书馆':
                    i += 2
                    isbefore = False
                    continue
                if isbefore and route[i + 1] != '图书馆':
                    if self.distance_L[route[i]] < self.distance_L[route[i + 1]]:
                        route[i], route[i + 1] = route[i + 1], route[i]
                if isbefore == False and route[i - 1] != '图书馆':
                    if self.distance_L[route[i]] < self.distance_L[route[i - 1]]:
                        route[i], route[i - 1] = route[i - 1], route[i]
        return route

    def fit_route(self, route):
        if len(route) > 0:
            result = [route[0]]
        else:
            result = []
        for i in range(len(route) - 1):
            result[len(result):len(result)] = self.find_route(route[i], route[i + 1])

        return result

    def plan_delivery_route(self, only_return=False):
        if self.tasks:
            self.tasks_store = copy.deepcopy(self.tasks)
        else:
            self.tasks = copy.deepcopy(self.tasks_store)






# 初始化图和任务
graph_with_tasks = WeightedGraphWithTasks()

# 添加地点间的道路及权重
edges_road_weights = {
    # 第一列
    ('充电站1', '四美楼'): {'weight': 0.6},
    ('四美楼', '芳邻楼'): {'weight': 0.3},
    ('芳邻楼', '凌云楼'): {'weight': 1.1},
    ('凌云楼', '远山楼'): {'weight': 0.5},
    ('远山楼', '重霄楼'): {'weight': 0.8},
    # 第二列
    ('北辰楼', '弥津楼'): {'weight': 0.5},
    ('弥津楼', '映雪楼'): {'weight': 1.2},
    ('映雪楼', '高洁楼'): {'weight': 1.8},
    ('高洁楼', '南溟楼'): {'weight': 0.8},
    ('南溟楼', '长洲楼'): {'weight': 1.0},
    # 第三列
    ('秋水楼', '临川楼'): {'weight': 0.4},
    ('临川楼', '路口1'): {'weight': 1.1},  # 有缺地点
    ('路口1', '图书馆'): {'weight': 2.2},
    ('图书馆', '景明楼'): {'weight': 0.7},
    ('景明楼', '清风楼'): {'weight': 1.0},
    # 第四列
    ('皓月楼', '耸翠楼'): {'weight': 0.9},
    ('耸翠楼', '朱华楼'): {'weight': 0.4},
    ('路口2', '绿竹楼'): {'weight': 0.5},  # 有缺地点
    ('绿竹楼', '沉壁楼'): {'weight': 0.6},
    # 第五列
    ('雅望楼', '朝晖楼'): {'weight': 0.3},
    ('朝晖楼', '流丹楼'): {'weight': 1.1},
    ('流丹楼', '俊采楼'): {'weight': 2.1},
    ('俊采楼', '汀兰楼'): {'weight': 0.8},
    ('汀兰楼', '兰亭楼'): {'weight': 1.1},
    # 第六列
    ('郁青楼', '星耀楼'): {'weight': 0.4},
    ('星耀楼', '万千楼'): {'weight': 0.9},
    ('万千楼', '东隅楼'): {'weight': 1.4},
    ('东隅楼', '长风楼'): {'weight': 0.6},
    ('长风楼', '充电站2'): {'weight': 0.5},
    ##第一行
    ('充电站1', '北辰楼'): {'weight': 0.7},
    ('北辰楼', '秋水楼'): {'weight': 0.7},
    ('秋水楼', '皓月楼'): {'weight': 0.5},
    ('皓月楼', '雅望楼'): {'weight': 1.1},
    ('雅望楼', '郁青楼'): {'weight': 0.5},
    ##第二行
    ('四美楼', '弥津楼'): {'weight': 0.6},
    ('弥津楼', '临川楼'): {'weight': 1.1},
    ('临川楼', '耸翠楼'): {'weight': 0.7},
    ('耸翠楼', '朝晖楼'): {'weight': 0.6},
    ('朝晖楼', '星耀楼'): {'weight': 0.9},
    ##第三行
    ('芳邻楼', '映雪楼'): {'weight': 1.5},
    ('映雪楼', '路口1'): {'weight': 1.3},  # 有缺地点
    ('路口1', '朱华楼'): {'weight': 1.0},
    ('朱华楼', '流丹楼'): {'weight': 0.3},
    ('流丹楼', '万千楼'): {'weight': 0.8},
    ##第四行
    ('凌云楼', '高洁楼'): {'weight': 1.7},
    ('高洁楼', '图书馆'): {'weight': 0.7},
    ('图书馆', '路口2'): {'weight': 0.4},  # 有缺地点
    ('路口2', '俊采楼'): {'weight': 0.8},
    ('俊采楼', '东隅楼'): {'weight': 0.7},
    ##第五行
    ('远山楼', '南溟楼'): {'weight': 2.0},
    ('南溟楼', '景明楼'): {'weight': 1.0},
    ('景明楼', '绿竹楼'): {'weight': 0.5},
    ('绿竹楼', '汀兰楼'): {'weight': 0.6},
    ('汀兰楼', '长风楼'): {'weight': 0.5},
    ##第六行
    ('重霄楼', '长洲楼'): {'weight': 0.7},
    ('长洲楼', '清风楼'): {'weight': 0.6},
    ('清风楼', '沉壁楼'): {'weight': 0.6},
    ('沉壁楼', '兰亭楼'): {'weight': 0.4},
    ('兰亭楼', '充电站2'): {'weight': 0.3},
}

# 使用add_edge方法添加边和权重到图中
for (node1, node2), details in edges_road_weights.items():
    graph_with_tasks.add_edge(node1, node2, f"{node1}到{node2}的路", details['weight'])

# 添加任务
# 第一列

def add():
    graph_with_tasks.add_task('四美楼', 3, 0)  # 3本书要还，0本书要借
    graph_with_tasks.add_task('芳邻楼', 4, 1)
    graph_with_tasks.add_task('凌云楼', 2, 0)
    graph_with_tasks.add_task('远山楼', 5, 2)
    graph_with_tasks.add_task('重霄楼', 6, 0)
    graph_with_tasks.add_task('北辰楼', 6, 2)
    graph_with_tasks.add_task('弥津楼', 5, 0)
    graph_with_tasks.add_task('映雪楼', 2, 0)
    graph_with_tasks.add_task('高洁楼', 4, 0)
    graph_with_tasks.add_task('南溟楼', 3, 1)
    graph_with_tasks.add_task('长洲楼', 6, 0)
    graph_with_tasks.add_task('秋水楼', 4, 3)
    graph_with_tasks.add_task('临川楼', 3, 0)
    graph_with_tasks.add_task('景明楼', 6, 0)
    graph_with_tasks.add_task('清风楼', 2, 0)
    graph_with_tasks.add_task('皓月楼', 7, 2)
    # 第二列
    graph_with_tasks.add_task('耸翠楼', 4, 0)
    graph_with_tasks.add_task('朱华楼', 2, 3)
    graph_with_tasks.add_task('绿竹楼', 5, 0)
    graph_with_tasks.add_task('沉壁楼', 6, 0)
    graph_with_tasks.add_task('雅望楼', 5, 2)
    graph_with_tasks.add_task('朝晖楼', 3, 0)
    graph_with_tasks.add_task('流丹楼', 8, 0)
    graph_with_tasks.add_task('俊采楼', 3, 0)
    graph_with_tasks.add_task('汀兰楼', 6, 2)
    graph_with_tasks.add_task('兰亭楼', 2, 0)
    graph_with_tasks.add_task('郁青楼', 3, 0)
    graph_with_tasks.add_task('星耀楼', 4, 0)
    graph_with_tasks.add_task('万千楼', 2, 2)
    graph_with_tasks.add_task('东隅楼', 1, 0)
    graph_with_tasks.add_task('长风楼', 5, 0)
# 自己加的第三列
# graph_with_tasks.add_task('路口1', 0, 0)
# graph_with_tasks.add_task('路口2', 0, 0)
# graph_with_tasks.add_task('充电站1', 0, 0)
# graph_with_tasks.add_task('充电站2', 0, 0)
# graph_with_tasks.add_task('图书馆', 0, 0)
add()
# 规划配送路线
robot_specs = {
    'A': {'start_node': '充电站2', 'max_capacity': 10, 'speed': 8},
    'B': {'start_node': '充电站1', 'max_capacity': 10, 'speed': 10},
}

graph_with_tasks.init_num_to_node()#初始化taskstore
if graph_with_tasks.tasks:
    graph_with_tasks.tasks_store = copy.deepcopy(graph_with_tasks.tasks)
else:
    graph_with_tasks.tasks = copy.deepcopy(graph_with_tasks.tasks_store)
def init(num_robotA,num_robotB): #15是图书馆
    global graph_with_tasks
    taskA=[]
    taskB=[]
    task_store=graph_with_tasks.tasks_store
    numbers = list(range(0, 36))
    numbers.remove(15)
    numbers.remove(14)
    numbers.remove(21)
    numbers.remove(0)
    numbers.remove(35)
    for i in range(16):
        taskA.append(numbers[i])
        random.shuffle(taskA)
    taskB=[x for x in numbers if x not in taskA]
    random.shuffle(taskB)
    return taskA , taskB

def new_solution(lt1,lt2,T):
    result = lt1.copy()
    num_swaps = max(math.floor(T),10)
    for _ in range(num_swaps):
        # 随机选择两个索引位置
        i = random.randint(0, len(result) - 1)
        j = random.randint(0, len(result) - 1)
        # 交换这两个位置的元素
        result[i], result[j] = result[j], result[i]
    result = lt2.copy()
    num_swaps = math.floor(T)
    for _ in range(num_swaps):
        # 随机选择两个索引位置
        i = random.randint(0, len(result) - 1)
        j = random.randint(0, len(result) - 1)
        # 交换这两个位置的元素
        result[i], result[j] = result[j], result[i]

    result1 = lt1.copy()
    result2 = lt2.copy()

    # 进行 T 次随机交换
    for _ in range(num_swaps):
        # 随机选择两个索引位置,分别来自两个列表
        i = random.randint(0, len(result1) - 1)
        j = random.randint(0, len(result2) - 1)

        # 交换这两个位置的元素
        result1[i], result2[j] = result2[j], result1[i]
        if random.random() < len(result1)/(len(result2)+len(result1)):
            if len(result1)< 10:
                result1.append(result2.pop(j))
            else:
                result2.append(result1.pop(i))
        else:
            if len(result2)< 10:
                result2.append(result1.pop(j))
            else:
                result1.append(result2.pop(j))

    return result1, result2
def Task1_constraint(lt1,lt2):
    global graph_with_tasks
    TaskA = lt1.copy()
    TaskB = lt2.copy()
    routeA=[35,35]
    routeB=[0,0]
    sum = 0
    i=0
    while i < len(TaskA)-1:
        sum+=graph_with_tasks.tasks_store[graph_with_tasks.num_to_node[TaskA[i]]]['return']
        if sum >=10:
            TaskA[i:i]=[15]
            sum=0
            i+=2
        else:
            i+=1
    sum = 0
    i=0
    while i < len(TaskB)-1:
        sum+=graph_with_tasks.tasks_store[graph_with_tasks.num_to_node[TaskB[i]]]['return']
        if sum >10:
            sum = 0
            TaskB[i:i]=[15]
            i+=2
        else:
            i+=1
    routeA = routeA[:1] + TaskA + routeA[1:]
    routeB = routeB[:1] + TaskB + routeB[1:]
    if routeA[-2]!=[15]:
        routeA = routeA[:-1] + [15] + routeA[-1:]
    if routeB[-2] != [15]:
        routeB = routeB[:-1] + [15] + routeB[-1:]
    return routeA,routeB

def Task2_constraint(lt1,lt2):

    global graph_with_tasks
    tasks_store = graph_with_tasks.tasks_store.copy()
    TaskA = lt1.copy()
    TaskB = lt2.copy()
    routeA = [35, 35]
    routeB = [0, 0]
    sum1 = 0
    sum2 = 0
    i = 0
    while i < len(TaskA) - 1:
        sum1 += tasks_store[graph_with_tasks.num_to_node[TaskA[i]]]['return']
        sum2 -= tasks_store[graph_with_tasks.num_to_node[TaskA[i]]]['borrow']
        tasks_store[graph_with_tasks.num_to_node[TaskA[i]]]['borrow']=0
        if sum1 + sum2 >= 10 or sum2 < 0:
            sum1 = tasks_store[graph_with_tasks.num_to_node[TaskA[i]]]['return']
            sum2 = min(3,sum_dict_values([graph_with_tasks.num_to_node[num] for num in lt1],tasks_store))  #除了刚刚那个点的书在额外带3本
            TaskA[i:i] = [15]
            i += 2
        else:
            i += 1
    sum1 = 0
    sum2 = 0
    i = 0
    while i < len(TaskB) - 1:
        sum1 += tasks_store[graph_with_tasks.num_to_node[TaskB[i]]]['return']
        sum2 -= tasks_store[graph_with_tasks.num_to_node[TaskB[i]]]['borrow']
        if sum1 + sum2 >= 10 or sum2 < 0:
            sum1 = tasks_store[graph_with_tasks.num_to_node[TaskB[i]]]['return']
            sum2 = min(3,sum_dict_values([graph_with_tasks.num_to_node[num] for num in lt2],tasks_store))
            TaskB[i:i] = [15]
            i += 2
        else:
            i += 1
    routeA = routeA[:1] + TaskA + routeA[1:]
    routeB = routeB[:1] + TaskB + routeB[1:]
    if routeA[-2]!=[15]:
        routeA = routeA[:-1] + [15] + routeA[-1:]
    if routeB[-2] != [15]:
        routeB = routeB[:-1] + [15] + routeB[-1:]
    return routeA,routeB


def sum_dict_values(key_list, my_dict):

    total_sum = 0

    for key in key_list:
        if key in my_dict:
            total_sum += my_dict[key]['borrow']

    return total_sum
def f(tA,tB):
    global graph_with_tasks
    routeA=[graph_with_tasks.num_to_node[num] for num in tA ]
    routeB=[graph_with_tasks.num_to_node[num] for num in tB ]
    routeA=graph_with_tasks.fit_route(routeA)
    routeB=graph_with_tasks.fit_route(routeB)
    TA=graph_with_tasks.calculate_total_time(routeA,8)
    TB=graph_with_tasks.calculate_total_time(routeB,10)
    return max(TA,TB)

tA,tB = init(2,2)
tA,tB =Task1_constraint(tA,tB)

iteration_times = []
iteration_route=[]
iteration =0
def CVRP_SA():
    global iteration_times
    global iteration_route
    global iteration
    init_solution1,init_solution2=init(2,2)
    T=100  # 初始温度，（加热过程后的路径作为）初始路径

    T_down_rate = 0.99  # 温度下降速率
    T_end = 0.01  # 终止温度
    K = 1  # 内循环次数
    old_path1, old_path2 = new_solution(init_solution1, init_solution2,T)
    old_path1x, old_path2x = Task1_constraint(old_path1, old_path2)
    min_v=f(old_path1x, old_path2x)
    S=[]#更好的解集
    S.append((old_path1, old_path2))
    n=0

    while T > T_end:  # 模拟退火直到温度小于终止温度
        for i in range(K):

            new_path1,new_path2 = new_solution(old_path1, old_path2,T)  # 生成新路径
            new_path1x, new_path2x = Task2_constraint(new_path1,new_path2)
            old_path1x, old_path2x = Task2_constraint(old_path1, old_path2)
            currrt_v=f(old_path1x, old_path2x)
            new_v=f(new_path1x, new_path2x)
            if new_v<=currrt_v:  # 如果最优路径比之前计算的结果更好，就接受
                old_path1, old_path2 = new_path1,new_path2
                iteration_times.append(new_v)
                iteration_route.append((new_path1,new_path2))
                iteration += 1
                if new_v<=min_v:
                    min_v=new_v
                    S.append((new_path1,new_path2))

            elif random.random()<math.exp(-(new_v - currrt_v) / T):
                old_path1, old_path2 = new_path1, new_path2
                iteration_times.append(new_v)
                iteration_route.append((new_path1, new_path2))
                iteration += 1
            else:
                old_path1, old_path2 = S[-1][0], S[-1][1]
                a, b = Task2_constraint(S[-1][0], S[-1][1])
                f_a=f(a,b)
                iteration_route.append((S[-1][0], S[-1][1]))
                iteration_times.append(f_a)
                iteration += 1


        shortest_dis=S[-1]    # 每次循环下的最优解

        T *= T_down_rate  # 每次循环后，以一定的下降速率降温
        print('best_dis', shortest_dis)  # 将执行过程print出来，可以时刻监控T值和当前的最优距离
        print(T)
        a,b=Task2_constraint(S[-1][0],S[-1][1])
        f_a = f(a, b)
        print(f_a)


    return

CVRP_SA()


node_positions = {
    # 第一列
    '充电站1': (0, 5),
    '四美楼': (0, 4),
    '芳邻楼': (0, 3),
    '凌云楼': (0, 2),
    '远山楼': (0, 1),
    '重霄楼': (0, 0),
    # 第二列
    '北辰楼': (1, 5),
    '弥津楼': (1, 4),
    '映雪楼': (1, 3),
    '高洁楼': (1, 2),
    '南溟楼': (1, 1),
    '长洲楼': (1, 0),
    # 第三列
    '秋水楼': (2, 5),
    '临川楼': (2, 4),
    '路口1': (2, 3),
    '图书馆': (2, 2),
    '景明楼': (2, 1),
    '清风楼': (2, 0),
    # 第四列
    '皓月楼': (3, 5),
    '耸翠楼': (3, 4),
    '朱华楼': (3, 3),
    '路口2': (3, 2),
    '绿竹楼': (3, 1),
    '沉壁楼': (3, 0),
    # 第五列
    '雅望楼': (4, 5),
    '朝晖楼': (4, 4),
    '流丹楼': (4, 3),
    '俊采楼': (4, 2),
    '汀兰楼': (4, 1),
    '兰亭楼': (4, 0),
    # 第六列
    '郁青楼': (5, 5),
    '星耀楼': (5, 4),
    '万千楼': (5, 3),
    '东隅楼': (5, 2),
    '长风楼': (5, 1),
    '充电站2': (5, 0),
}



# def visualize_graph(graph_with_tasks):
#     G = nx.Graph()
#
#     # 添加边和权重到网络X图中
#     for node1, neighbors in graph_with_tasks.graph.items():
#         for node2, details in neighbors.items():
#             G.add_edge(node1, node2, weight=details['weight'])
#
#     # 设置节点位置
#     pos = node_positions
#
#     # 绘制无向图
#     nx.draw_networkx_nodes(G, pos, node_size=800, node_color='skyblue', edgecolors='black', linewidths=1.4)
#     nx.draw_networkx_edges(G, pos, edgelist=G.edges(), edge_color='gray', width=1.5, alpha=0.6)
#     nx.draw_networkx_labels(G, pos, font_size=7, font_family="sans-serif", font_color='black')
#
#     # 显示权重
#     labels = nx.get_edge_attributes(G, 'weight')
#     nx.draw_networkx_edge_labels(G, pos, edge_labels=labels, font_color='red')
#
#     plt.axis('off')
#     plt.title('送货路线图', fontsize=20)
#     plt.show()
#
#
# # 在规划完路线后，调用visualize_graph函数进行可视化
# visualize_graph(graph_with_tasks)
#
# # 动画显示
#
# edge_colors = {}
# arrows = []
#
#
# def update(num, G, pos, edges_A, edges_B, line_A, line_B):
#     global arrows
#
#     # 清除之前的线条
#     line_A.set_data([], [])
#     line_B.set_data([], [])
#
#     # 删除旧的箭头
#     while arrows:
#         arrows.pop().remove()
#
#     # 更新每一帧的路线
#     for edge in edges_A[num:num + 1]:
#         color = 'blue'
#         line_A.set_color(color)
#         line_A.set_data([pos[edge[0]][0], pos[edge[1]][0]], [pos[edge[0]][1], pos[edge[1]][1]])
#         arrow = plt.arrow(pos[edge[0]][0], pos[edge[0]][1], pos[edge[1]][0] - pos[edge[0]][0],
#                           pos[edge[1]][1] - pos[edge[0]][1], color=color, shape='full', lw=0, length_includes_head=True,
#                           head_width=.2)
#         arrows.append(arrow)
#
#     for edge in edges_B[num:num + 1]:
#         color = 'red'
#         line_B.set_color(color)
#         line_B.set_data([pos[edge[0]][0], pos[edge[1]][0]], [pos[edge[0]][1], pos[edge[1]][1]])
#         arrow = plt.arrow(pos[edge[0]][0], pos[edge[0]][1], pos[edge[1]][0] - pos[edge[0]][0],
#                           pos[edge[1]][1] - pos[edge[0]][1], color=color, shape='full', lw=0, length_includes_head=True,
#                           head_width=.2)
#         arrows.append(arrow)
#
#     return line_A, line_B
#
#     # 将路线转换为边的列表
#     edges_A = [(route_A[i], route_A[i + 1]) for i in range(len(route_A) - 1)]
#     edges_B = [(route_B[i], route_B[i + 1]) for i in range(len(route_B) - 1)]

# def visualize_routes(graph_with_tasks, route_A, route_B):
#     G = nx.Graph()
#
#     # 添加边和权重到网络X图中
#     for node1, neighbors in graph_with_tasks.graph.items():
#         for node2, details in neighbors.items():
#             G.add_edge(node1, node2, weight=details['weight'])
#
#     # 设置节点位置
#     pos = node_positions
#
#     # 绘制无向图
#     nx.draw_networkx_nodes(G, pos, node_size=800, node_color='skyblue', edgecolors='black', linewidths=1.4)
#     nx.draw_networkx_edges(G, pos, edgelist=G.edges(), edge_color='gray', width=1.5, alpha=0.6)
#     nx.draw_networkx_labels(G, pos, font_size=7, font_family="sans-serif", font_color='black')
#
#     # 显示权重
#     labels = nx.get_edge_attributes(G, 'weight')
#     nx.draw_networkx_edge_labels(G, pos, edge_labels=labels, font_color='red')
#
#     # 将路线转换为边的列表
#     edges_A = [(route_A[i], route_A[i + 1]) for i in range(len(route_A) - 1)]
#     edges_B = [(route_B[i], route_B[i + 1]) for i in range(len(route_B) - 1)]
#
#     # 创建两条路线的线对象
#     line_A, = plt.plot([], [], color='blue', linewidth=2.5, alpha=0.6)
#     line_B, = plt.plot([], [], color='red', linewidth=2.5, alpha=0.6)
#
#     # 创建动画
#     ani = animation.FuncAnimation(plt.gcf(), update, frames=len(edges_A),
#                                   fargs=(G, pos, edges_A, edges_B, line_A, line_B), interval=500)
#
#     plt.axis('off')
#     plt.title('送货路线图', fontsize=20)
#     plt.show()


# 在规划完路线后，调用visualize_routes函数进行可视化
# visualize_routes(graph_with_tasks, route_A, route_B)
def plot_iteration_times(iteration_times):
    plt.figure(figsize=(10, 6))
    plt.plot(iteration_times, linestyle='-', color='b', label='时间')
    plt.title('迭代次数与配送时间关系', fontsize=24, fontweight='bold')
    plt.xlabel('迭代次数', fontsize=14, fontweight='bold')
    plt.ylabel('时间 (h)', fontsize=14, fontweight='bold')
    plt.grid(True, linestyle='--', alpha=0.6)
    plt.legend(loc='best')
    plt.show()

plot_iteration_times(iteration_times)

# graph_with_tasks.generate_matrix()
# graph_with_tasks.visualize_matrix()
# print(iteration_times[-1])